<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>文件内容处理 API 测试 (Minerva)</title>
    <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
    <!-- 引入 json-formatter-js -->
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/json-formatter-js@2.3.4/dist/json-formatter.min.css">
    <script src="https://cdn.jsdelivr.net/npm/json-formatter-js@2.3.4/dist/json-formatter.cjs.js"></script>
    <style>
        body { font-family: sans-serif; margin: 20px; background-color: #f4f4f4; color: #333; }
        .container { background-color: #fff; padding: 20px; border-radius: 8px; box-shadow: 0 0 10px rgba(0,0,0,0.1); margin-bottom: 20px; }
        label { display: block; margin-bottom: 8px; font-weight: bold; }
        input[type="file"], input[type="text"] { width: calc(100% - 22px); padding: 10px; margin-bottom: 15px; border: 1px solid #ccc; border-radius: 4px; box-sizing: border-box;}
        button { background-color: #007bff; color: white; padding: 10px 15px; border: none; border-radius: 4px; cursor: pointer; font-size: 16px; margin-right: 10px; margin-bottom: 5px; }
        button:hover { background-color: #0056b3; }
        button:disabled { background-color: #ccc; cursor: not-allowed;}
        
        /* API 响应使用 JSON Formatter */
        #raw_api_response_container { /* 注意ID已更改为容器 */
            background-color: #e9e9e9; /* 可以保留背景色，或让 formatter 控制 */
            padding: 15px;
            border-radius: 4px;
            overflow-x: auto;
            max-height: 400px; /* 增加一点高度 */
            margin-top: 10px; /* 给上面元素一点空间 */
        }
        /* 针对 JSON Formatter 内的 pre 标签，如果需要微调 */
        #raw_api_response_container .json-formatter-open > pre, 
        #raw_api_response_container .json-formatter-row > pre {
             white-space: pre-wrap !important; /* 强制内容换行 */
             word-wrap: break-word !important;
        }

        .markdown-rendered-output {
            background-color: #e0e0e0;
            padding: 15px;
            border: 1px solid #ccc;
            border-radius: 4px;
            overflow-y: auto;
            max-height: 400px;
            margin-bottom: 15px;
        }
        .markdown-rendered-output h1, .markdown-rendered-output h2, .markdown-rendered-output h3 {
            margin-top: 1em; margin-bottom: 0.5em; padding-bottom: 0.2em; border-bottom: 1px solid #ddd;
        }
        .markdown-rendered-output p { margin-bottom: 1em; line-height: 1.6; }
        .markdown-rendered-output ul, .markdown-rendered-output ol { margin-left: 20px; margin-bottom: 1em; }
        .markdown-rendered-output code {
            background-color: rgba(27,31,35,.07); border-radius: 3px; padding: .2em .4em; font-size: 85%;
        }
        .markdown-rendered-output pre > code {
            display: block; padding: 10px; margin-bottom: 1em; font-size: 90%; line-height: 1.45;
            background-color: #f7f7f7; border-radius: 3px; overflow: auto; white-space: pre;
        }

        .results-section { margin-top: 20px; border-top: 1px solid #eee; padding-top: 20px;}
        .file-link { display: block; margin-bottom: 5px; }
        .spinner, .request-spinner { display: none; margin: 10px auto; width: 30px; height: 30px; border: 3px solid #f3f3f3; border-top: 3px solid #3498db; border-radius: 50%; animation: spin 1s linear infinite; }
        @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
        
        .request-actions button { background-color: #17a2b8; } 
        .request-actions button:hover { background-color: #117a8b; }
        .request-results-container { margin-top: 15px; }
        .request-results-container h4 { margin-bottom: 5px; }
        .request-results-container .json-formatter-container { /* 目标 json-formatter-js 自动生成的容器 */
            background-color: #f0f0f0;
            padding: 10px;
            border-radius: 4px;
            max-height: 350px;
            overflow: auto;
        }

    </style>
</head>
<body>
    <div class="container">
        <h1>文件内容处理 (Minerva OCR)</h1>
        <label for="api_base_url">API 基础 URL:</label>
        <input type="text" id="api_base_url" value="http://127.0.0.1:5055/minerva">

        <label for="file_input">选择文件 (PDF, PNG, JPG, BMP, TIFF, GIF):</label>
        <input type="file" id="file_input" accept=".pdf,image/png,image/jpeg,image/bmp,image/tiff,image/gif">

        <button id="process_file_button" onclick="uploadAndProcessFile()">上传并处理文件</button>
        <div id="spinner" class="spinner"></div>

        <div id="results_output_section" class="results-section" style="display:none;">
            <h2>处理结果:</h2>
            <div id="status_message"></div>
            <h3>Markdown 内容 (渲染):</h3>
            <div id="markdown_content_display" class="markdown-rendered-output"></div>
            
            <h3>生成的文件:</h3>
            <div id="generated_files_links"></div>
            <button id="download_all_button" style="margin-top:10px; background-color: #28a745; display:none;" onclick="downloadAllResults()">下载所有结果 (ZIP)</button>
            
            <div class="request-actions" style="margin-top: 15px;">
                 <button id="extract_indicators_button" style="display:none;" onclick="extractDataWithDemo('indicators')">提取技术指标</button>
                 <button id="extract_terms_button" style="display:none;" onclick="extractDataWithDemo('terms')">提取术语定义</button>
            </div>
            <div id="request_spinner" class="request-spinner"></div>

            <div class="request-results-container">
                <div id="indicators_result_area" style="display:none;">
                    <h4>技术指标提取结果:</h4>
                    <div id="indicators_content" class="json-formatter-container"></div>
                </div>
                <div id="terms_result_area" style="display:none;">
                    <h4>术语定义提取结果:</h4>
                    <div id="terms_content" class="json-formatter-container"></div>
                </div>
            </div>
        </div>
        <h3>原始 API 响应:</h3>
        <div id="raw_api_response_container"> <!-- 改为 div 容器 -->
            <p>此处将显示 API 的原始 JSON 响应...</p>
        </div>
    </div>

    <script>
        let currentRequestId = null; 

        marked.setOptions({
            gfm: true, breaks: true, sanitize: true, smartLists: true, smartypants: false,
        });

        // JSON Formatter 配置
        const formatterConfig = {
            hoverPreviewEnabled: true,
            hoverPreviewArrayCount: 100,
            hoverPreviewFieldCount: 5,
            theme: '', // 'default' or 'dark'
            animateOpen: true,
            animateClose: true,
            useToJSON: true
        };

        function displayApiResponse(containerId, data, initialMessage = "等待响应...") {
            const container = document.getElementById(containerId);
            container.innerHTML = ''; // 清空旧内容

            if (data === null || data === undefined) {
                const p = document.createElement('p');
                p.textContent = initialMessage;
                container.appendChild(p);
                return;
            }

            try {
                const formatter = new JSONFormatter(data, 1, formatterConfig);
                container.appendChild(formatter.render());
            } catch (e) {
                console.error(`Error rendering JSON for ${containerId}:`, e, data);
                const preError = document.createElement('pre');
                preError.textContent = "无法格式化API响应。原始数据：\n" + JSON.stringify(data, null, 2);
                preError.style.color = 'red';
                container.appendChild(preError);
            }
        }


        async function uploadAndProcessFile() {
            const apiBaseUrlInput = document.getElementById('api_base_url');
            const fileInput = document.getElementById('file_input');
            const processButton = document.getElementById('process_file_button');
            const spinner = document.getElementById('spinner');

            const resultsOutputSection = document.getElementById('results_output_section');
            const rawApiResponseContainer = document.getElementById('raw_api_response_container');
            const statusMessageDisplay = document.getElementById('status_message');
            const markdownContentDisplay = document.getElementById('markdown_content_display'); 
            const generatedFilesLinksDisplay = document.getElementById('generated_files_links');
            const downloadAllButton = document.getElementById('download_all_button');
            const extractIndicatorsButton = document.getElementById('extract_indicators_button');
            const extractTermsButton = document.getElementById('extract_terms_button');
            const indicatorsResultArea = document.getElementById('indicators_result_area');
            const indicatorsContentContainer = document.getElementById('indicators_content');
            const termsResultArea = document.getElementById('terms_result_area');
            const termsContentContainer = document.getElementById('terms_content');


            const baseUrl = apiBaseUrlInput.value.trim();
            const file = fileInput.files[0];

            processButton.disabled = true;
            spinner.style.display = 'block';
            resultsOutputSection.style.display = 'none'; 
            displayApiResponse('raw_api_response_container', null, '正在上传和处理文件...');
            
            statusMessageDisplay.textContent = '';
            markdownContentDisplay.innerHTML = ''; 
            generatedFilesLinksDisplay.innerHTML = '';
            downloadAllButton.style.display = 'none';
            extractIndicatorsButton.style.display = 'none';
            extractTermsButton.style.display = 'none';
            indicatorsResultArea.style.display = 'none';
            indicatorsContentContainer.innerHTML = '';
            termsResultArea.style.display = 'none';
            termsContentContainer.innerHTML = '';
            currentRequestId = null;

            if (!baseUrl) {
                displayApiResponse('raw_api_response_container', { error: "API 基础 URL 不能为空。" });
                processButton.disabled = false; spinner.style.display = 'none'; return;
            }
            if (!file) {
                displayApiResponse('raw_api_response_container', { error: "请选择一个文件。" });
                processButton.disabled = false; spinner.style.display = 'none'; return;
            }

            let apiUrl = '';
            let fileTypeLabel = '';
            if (file.type === 'application/pdf') {
                apiUrl = `${baseUrl}/process_pdf`; fileTypeLabel = 'PDF';
            } else if (file.type.startsWith('image/')) {
                apiUrl = `${baseUrl}/process_image`; fileTypeLabel = '图片';
            } else {
                displayApiResponse('raw_api_response_container', { error: `不支持的文件类型 - ${file.type}。` });
                processButton.disabled = false; spinner.style.display = 'none'; return;
            }

            const formData = new FormData();
            formData.append('file', file);

            try {
                const response = await fetch(apiUrl, { method: 'POST', body: formData });
                const data = await response.json(); // data 已经是 JS 对象
                displayApiResponse('raw_api_response_container', data);

                if (response.ok && data.success) {
                    resultsOutputSection.style.display = 'block';
                    statusMessageDisplay.textContent = `成功: ${fileTypeLabel} 文件处理完成。${data.message || ''}`;
                    statusMessageDisplay.style.color = 'green';
                    
                    if (data.markdown_content) {
                        markdownContentDisplay.innerHTML = marked.parse(data.markdown_content);
                    } else {
                        markdownContentDisplay.innerHTML = "<p>无 Markdown 内容。</p>";
                    }
                    
                    currentRequestId = data.request_id;

                    if (data.generated_files && currentRequestId) {
                        generatedFilesLinksDisplay.innerHTML = ''; // 清空旧链接
                        downloadAllButton.style.display = 'inline-block'; 
                        extractIndicatorsButton.style.display = 'inline-block';
                        extractTermsButton.style.display = 'inline-block';

                        const baseDownloadUrl = `${baseUrl}/download/${currentRequestId}/`;
                        for (const key in data.generated_files) {
                            const filenameOrFolder = data.generated_files[key];
                            if (filenameOrFolder === null || filenameOrFolder === undefined) continue; 

                            if (key.endsWith("_folder")) { 
                                const folderName = filenameOrFolder; 
                                let itemCount = 0; // 默认为0，避免显示“一些”
                                if (key === "images_folder" && data.generated_files.num_images !== undefined) {
                                    itemCount = data.generated_files.num_images;
                                } else if (key === "processed_images_folder" && data.generated_files.num_processed_images !== undefined) {
                                    itemCount = data.generated_files.num_processed_images;
                                }
                                if (itemCount > 0) { // 只在有项目时显示
                                     generatedFilesLinksDisplay.innerHTML += `<p>包含 ${itemCount} 个项目在 '${folderName}' 文件夹中 (ZIP内)。</p>`;
                                }
                            } else if (key !== "markdown_file" && key !== "actual_md_filename") { 
                                const link = document.createElement('a');
                                link.href = baseDownloadUrl + filenameOrFolder;
                                link.textContent = `下载 ${filenameOrFolder}`;
                                link.classList.add('file-link');
                                link.target = "_blank"; 
                                generatedFilesLinksDisplay.appendChild(link);
                            }
                        }
                    } else {
                         downloadAllButton.style.display = 'none';
                         extractIndicatorsButton.style.display = 'none';
                         extractTermsButton.style.display = 'none';
                    }
                } else {
                    resultsOutputSection.style.display = 'none'; 
                    statusMessageDisplay.textContent = `错误: ${data.error || `处理 ${fileTypeLabel} 失败。`}`;
                    statusMessageDisplay.style.color = 'red';
                }
            } catch (error) {
                console.error(`API 请求 (${fileTypeLabel}) 失败:`, error);
                displayApiResponse('raw_api_response_container', { error: `请求失败: ${error.message}\n请确保 API 服务运行且 URL 正确。` });
                resultsOutputSection.style.display = 'none';
            } finally {
                processButton.disabled = false;
                spinner.style.display = 'none';
                fileInput.value = ''; 
            }
        }

        async function extractDataWithDemo(type) { // type: 'indicators' or 'terms'
            if (!currentRequestId) {
                alert("请先成功处理一个文件。");
                return;
            }
            
            const baseUrl = document.getElementById('api_base_url').value.trim();
            const requestSpinner = document.getElementById('request_spinner');
            const resultAreaId = type === 'indicators' ? 'indicators_result_area' : 'terms_result_area';
            const contentContainerId = type === 'indicators' ? 'indicators_content' : 'terms_content';
            
            document.getElementById(resultAreaId).style.display = 'none';
            displayApiResponse(contentContainerId, null, '正在提取...'); // 清空并显示加载中
            requestSpinner.style.display = 'block';

            const apiUrl = `${baseUrl}/extract_request_data/${currentRequestId}/${type}`;

            try {
                const response = await fetch(apiUrl);
                const apiResponseData = await response.json(); 

                document.getElementById(resultAreaId).style.display = 'block';
                if (response.ok && apiResponseData.success) {
                    let requestContentString = apiResponseData.data; 
                    if (requestContentString) {
                        // --- 新增：清理包裹标记 ---
                        if (typeof requestContentString === 'string') {
                            // 移除常见的 Markdown 代码块标记
                            requestContentString = requestContentString.trim(); // 先去除首尾空格
                            if (requestContentString.startsWith("```json")) {
                                requestContentString = requestContentString.substring(7); // 跳过 "```json\n"
                            } else if (requestContentString.startsWith("```")) {
                                requestContentString = requestContentString.substring(3); // 跳过 "```\n"
                            }
                            if (requestContentString.endsWith("```")) {
                                requestContentString = requestContentString.substring(0, requestContentString.length - 3);
                            }
                            requestContentString = requestContentString.trim(); // 再次去除可能因移除标记产生的首尾空格
                        }
                        // --- 清理结束 ---

                        try {
                            const jsonData = JSON.parse(requestContentString); // 尝试解析为 JSON
                            displayApiResponse(contentContainerId, jsonData);
                        } catch (e) {
                            // 如果清理后仍然不是有效的 JSON，作为纯文本显示
                            const container = document.getElementById(contentContainerId);
                            container.innerHTML = ''; // 清空
                            const preText = document.createElement('pre');
                            preText.style.whiteSpace = 'pre-wrap';
                            preText.style.wordWrap = 'break-word';
                            preText.textContent = apiResponseData.data; // 显示原始未清理的，或者清理后的 requestContentString
                            // preText.textContent = requestContentString || "未能提取到相关内容，或内容非JSON格式。"; // 显示清理后的
                            container.appendChild(preText);
                            console.warn("返回的内容解析为JSON失败，将作为纯文本显示。原始:", apiResponseData.data, "清理后尝试解析的:", requestContentString, "错误:", e);
                        }
                    } else {
                         displayApiResponse(contentContainerId, null, "request API 未返回数据或数据为空。");
                    }
                } else {
                    displayApiResponse(contentContainerId, { error: `提取失败: ${apiResponseData.error || "未知错误"}` });
                }
            } catch (error) {
                console.error(`${type}提取失败:`, error);
                document.getElementById(resultAreaId).style.display = 'block';
                displayApiResponse(contentContainerId, { error: `请求提取服务失败: ${error.message}` });
            } finally {
                requestSpinner.style.display = 'none';
            }
        }

        function downloadAllResults() {
            const baseUrl = document.getElementById('api_base_url').value.trim();
            if (currentRequestId && baseUrl) {
                window.open(`${baseUrl}/download_all/${currentRequestId}`, '_blank');
            } else {
                alert('没有有效请求ID或API基础URL。');
            }
        }
    </script>
</body>
</html>